return {
  {
    event = "BufReadPost",
    -- 代码补全
    --[[
      除了 nvim-cmp 插件，其他的以 cmp- 开头的都是在指定补全的来源，
      就像 neovim 自带补全功能可以来源于当前buffer、路径、引用一样，
      该插件的补全项也来源于各个地方。
      例如 cmp-nvim-lsp来源于语言的 lsp 服务端、cmp-buffer来源于当前 buffer 、cmd-path来源于路径
    ]]
    "hrsh7th/nvim-cmp",
    dependencies = {
      -- autocompletion
      "neovim/nvim-lspconfig", -- lspconfig
      "hrsh7th/cmp-nvim-lsp",  -- { name = 'nvim_lsp'} LSP source for nvim-cmp

      "hrsh7th/cmp-buffer",    -- { name = 'buffer' }
      "hrsh7th/cmp-path",      -- { name = 'path' }
      "hrsh7th/cmp-cmdline",   -- { name = 'cmdline' }

      -- snippets
      "saadparwaiz1/cmp_luasnip",     -- LSP source for nvim-cmp
      "L3MON4D3/LuaSnip",             -- { name = 'luasnip' }
      "rafamadriz/friendly-snippets", -- 加载一些第三方的,比如自定义的,vscode的一些

      "ray-x/cmp-treesitter",         --   { name = 'treesitter' },

      "f3fora/cmp-spell",             -- { name = 'spell' }

      -- icon
      "onsails/lspkind.nvim",

      -- 成对符号补全
      "windwp/nvim-autopairs",
    },
    config = function()
      local cmp = require("cmp")
      local luasnip = require("luasnip")

      -- 依赖插件 nvim-autopairs
      local cmp_autopairs = require("nvim-autopairs.completion.cmp")
      -- 在选择函数或方法项后插入“（”
      cmp.event:on("confirm_done", cmp_autopairs.on_confirm_done())

      -- load friendly-snippets plugin 第三方,比如自定义的或者vscode的
      require("luasnip.loaders.from_vscode").lazy_load()
      -- require("luasnip.loaders.from_vscode").load({
      --   paths = {                                             -- load custom snippets
      --     vim.fn.stdpath("config") .. "/my-snippets"
      --   }
      -- })                                                      -- Load snippets from my-snippets folder

      -- Set up nvim-cmp.
      local has_words_before = function()
        unpack = unpack or table.unpack
        local line, col = unpack(vim.api.nvim_win_get_cursor(0))
        return col ~= 0
            and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil
      end

      cmp.setup({
        snippet = {
          -- 设置代码片段引擎，用于根据代码片段补全
          expand = function(args)
            luasnip.lsp_expand(args.body)
          end,
        },
        window = {
          completion = cmp.config.window.bordered(),
          documentation = cmp.config.window.bordered(),
        },
        mapping = cmp.mapping.preset.insert({
          -- -- 向上翻页
          -- ['<C-u>'] = cmp.mapping(cmp.mapping.scroll_docs(-4), { 'i', 'c' }),
          -- -- 向下翻页
          -- ['<C-d>'] = cmp.mapping(cmp.mapping.scroll_docs(4), { 'i', 'c' }),
          -- 显示补全提示
          -- ['<A-.>'] = cmp.mapping(cmp.mapping.complete(), { 'i', 'c' }),
          -- 取消补全窗口，esc也可以退出
          -- ['<A-,>'] = cmp.mapping({
          --   i = cmp.mapping.abort(),
          --   c = cmp.mapping.close(),
          -- }),

          ["<C-c>"] = cmp.mapping.abort(),            -- 取消补全窗口，esc也可以退出
          ["<C-b>"] = cmp.mapping.scroll_docs(-4),    -- 上移动
          ["<C-f>"] = cmp.mapping.scroll_docs(4),     -- 下移动
          ["<C-k>"] = cmp.mapping.select_prev_item(), -- 向上选择补全信息
          ["<C-j>"] = cmp.mapping.select_next_item(), -- 向下选择补全信息
          -- ["<C-Space>"] = cmp.mapping.complete(),     -- 补全提示选择
          ["<CR>"] = cmp.mapping.confirm({
            select = true,
            behavior = cmp.ConfirmBehavior.Replace,
          }), -- 确认使用某个补全项
          -- Tab 向下选择补全信息
          ["<Tab>"] = cmp.mapping(function(fallback)
            if cmp.visible() then
              cmp.select_next_item()
              -- 可以将 expand_or_jumpable() 调用替换为 expand_or_locally_jumpable()
              -- 区别在于只会跳到代码段区域内
            elseif luasnip.expand_or_jumpable() then
              luasnip.expand_or_jump()
              -- elseif luasnip.expand_or_locally_jumpable() then
              --   luasnip.expand_or_locally_jump()
              -- elseif luasnip.jumpable(1) then
              --   luasnip.jump(1)
            elseif has_words_before() then
              cmp.complete()
            else
              fallback()
            end
          end, { "i", "s" }),
          -- shift + Tab 向上选择补全信息
          ["<S-Tab>"] = cmp.mapping(function(fallback)
            if cmp.visible() then
              cmp.select_prev_item()
            elseif luasnip.jumpable(-1) then
              luasnip.jump(-1)
            else
              fallback()
            end
          end, { "i", "s" }),
        }),
        sources = cmp.config.sources({
          { name = "nvim_lsp" }, -- lsp cmp-nvim-lsp
          { name = "buffer" },
          -- {
          --   -- text within current buffer
          --   name = "buffer",
          --   option = {
          --     get_bufnrs = function()
          --       return vim.api.nvim_list_bufs()
          --     end,
          --   },
          -- },
          { name = "path" },    -- file system paths
          { name = "luasnip" }, -- snippets
          {
            name = 'spell',     -- cmp-spell
            -- vim.opt.spell = true
            -- vim.opt.spelllang = { 'en_us' }
            option = {
              keep_all_entries = false,
              enable_in_context = function()
                return require('cmp.config.context').in_treesitter_capture('spell')
              end,
            },
          },
          { name = "treesitter" },
          { name = "crates" }, -- rust -> crates
        }),
        -- 设置补全显示的格式
        formatting = {
          -- https://github.com/onsails/lspkind.nvim
          -- format = function(entry, vim_item)
          --   if vim.tbl_contains({ "path" }, entry.source.name) then
          --     local icon, hl_group =
          --         require("nvim-web-devicons").get_icon(entry:get_completion_item().label)
          --     if icon then
          --       vim_item.kind = icon
          --       vim_item.kind_hl_group = hl_group
          --       return vim_item
          --     end
          --   end
          --   return require("lspkind").cmp_format({ with_text = true })(entry, vim_item)
          -- end,
          format = require('lspkind').cmp_format({
            with_text = true, -- do not show text alongside icons
            maxwidth = 50,    -- prevent the popup from showing more than provided characters (e.g 50 will not show more than 50 characters)
            ellipsis_char = "...",
            before = function(entry, vim_item)
              -- Source 显示提示来源
              vim_item.menu = "[" .. string.upper(entry.source.name) .. "]"
              return vim_item
            end
          })
        },
        experimental = {
          -- 编辑器像有一个灰色倒影的预测用户输入书写提示
          ghost_text = true
        }
      })

      -- 根据文件类型来选择补全来源
      cmp.setup.filetype("gitcommit", {
        sources = cmp.config.sources({
          { name = "git" },
          { name = "buffer" },
        }),
      })
      -- 命令模式下输入 `/` 、`?`启用补全
      cmp.setup.cmdline({ "/", "?" }, {
        mapping = cmp.mapping.preset.cmdline(),
        sources = {
          { name = "buffer" },
        },
      })
      -- 命令模式下输入 `:` 启用补全
      cmp.setup.cmdline(":", {
        mapping = cmp.mapping.preset.cmdline(),
        sources = cmp.config.sources({
          { name = "path" },
          { name = "cmdline" },
        }),
      })

      vim.cmd([[
        set completeopt=menuone,noinsert,noselect
        highlight! default link CmpItemKind CmpItemMenuDefault
      ]])

      -- ==============custome snip start================
      luasnip.config.set_config({
        history = true,
        updateevents = "TextChanged,TextChangedI",
        enable_autosnippets = true,
      })

      local s = luasnip.snippet
      local t = luasnip.text_node
      local i = luasnip.insert_node
      local d = luasnip.dynamic_node
      local sn = luasnip.snippet_node

      luasnip.add_snippets("typescriptreact", {
        s("log", {
          t('console.log("'),
          i(1, ""),
          t('", '),
          i(2, ""),
          t(")"),
        }),
        s("rc", {
          t("export type "),
          i(1),
          t("Props = {}"),
          t({ "", "export function " }),
          d(2, function(args)
            return sn(nil, {
              i(1, args[1]),
            })
          end, { 1 }),
          t("(){return null}"),
        }),
      })
      -- ==============custome snip end================
    end,
  },
  {
    event = "VeryLazy",
    "onsails/lspkind-nvim",
    config = function()
      require("lspkind").init({
        mode = "symbol_text",
        preset = "codicons",
        symbol_map = {
          Text = "󰉿",
          Method = "󰆧",
          Function = "󰊕",
          Constructor = "",
          Field = "󰜢",
          Variable = "󰀫",
          Class = "󰠱",
          Interface = "",
          Module = "",
          Property = "󰜢",
          Unit = "󰑭",
          Value = "󰎠",
          Enum = "",
          Keyword = "󰌋",
          Snippet = "",
          Color = "󰏘",
          File = "󰈙",
          Reference = "󰈇",
          Folder = "󰉋",
          EnumMember = "",
          Constant = "󰏿",
          Struct = "󰙅",
          Event = "",
          Operator = "󰆕",
          TypeParameter = "",
        },
      })
    end,
  },
}
